﻿namespace System.ServiceModel.DomainServices.Client
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.Serialization;
    using System.Text;

    [DataContract]
    public abstract class Entity : INotifyDataErrorInfo, IEditableObject, INotifyPropertyChanged, IRevertibleChangeTracking, IChangeTracking
    {
        private System.ServiceModel.DomainServices.Client.EntityConflict _conflict;
        private EntityAction _customMethodInvocation;
        private EditSession _editSession;
        private IDictionary<string, IEntityRef> _entityRefs;
        private System.ServiceModel.DomainServices.Client.EntitySet _entitySet;
        private System.ServiceModel.DomainServices.Client.EntityState _entityState;
        private bool _hasChildChanges;
        private bool _isApplyingState;
        private bool _isDeserializing;
        private bool _isInferred;
        private bool _isMerging;
        private bool _isSubmitting;
        private bool _lastCanInvoke;
        private System.ServiceModel.DomainServices.Client.EntitySet _lastSet;
        private System.ServiceModel.DomainServices.Client.MetaType _metaType;
        private IDictionary<string, object> _originalValues;
        private Entity _parent;
        private AssociationAttribute _parentAssociation;
        private EntityAction _prevCustomMethodInvocation;
        private Action _setChangedCallback;
        private bool _trackChanges;
        private Dictionary<string, ComplexObject> _trackedInstances;
        private EntityValidationResultCollection _validationErrors;

        public event PropertyChangedEventHandler PropertyChanged;

        event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        protected Entity()
        {
        }

        protected void AcceptChanges()
        {
            if ((this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.Unmodified) || (this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.Detached))
            {
                this._editSession = null;
            }
            else
            {
                System.ServiceModel.DomainServices.Client.EntitySet lastSet = this.LastSet;
                if (lastSet != null)
                {
                    lastSet.EntityContainer.CompleteChildChanges(this, true);
                }
                if (this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.New)
                {
                    this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Unmodified;
                    if (lastSet != null)
                    {
                        lastSet.AddToCache(this);
                        if (this.IsEditing)
                        {
                            lastSet.UpdateRelatedAssociations(this, "EntityState");
                        }
                    }
                    this.StartTracking();
                }
                else if (this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.Modified)
                {
                    this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Unmodified;
                    this._originalValues = null;
                }
                else if (this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.Deleted)
                {
                    this.StopTracking();
                    if (lastSet != null)
                    {
                        lastSet.RemoveFromCache(this);
                    }
                    this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Detached;
                }
                if (lastSet != null)
                {
                    lastSet.TrackAsInteresting(this, false);
                }
                this._editSession = null;
                this.CustomMethodInvocation = null;
                if (this._validationErrors != null)
                {
                    this._validationErrors.Clear();
                }
                this.EntityConflict = null;
                this.IsInferred = false;
                this._hasChildChanges = false;
            }
        }

        internal void ApplyState(IDictionary<string, object> entityStateToApply)
        {
            this.ApplyState(entityStateToApply, LoadBehavior.RefreshCurrent);
        }

        private void ApplyState(IDictionary<string, object> entityStateToApply, LoadBehavior loadBehavior)
        {
            if (loadBehavior != LoadBehavior.KeepCurrent)
            {
                try
                {
                    this._isApplyingState = true;
                    ObjectStateUtility.ApplyState(this, entityStateToApply, this._originalValues, loadBehavior);
                }
                catch (TargetInvocationException exception)
                {
                    if (exception.InnerException != null)
                    {
                        throw exception.InnerException;
                    }
                    throw;
                }
                finally
                {
                    this._isApplyingState = false;
                }
            }
        }

        private void AttachComplexObjectInstance(MetaMember metaMember)
        {
            string name = metaMember.Member.Name;
            ComplexObject obj2 = null;
            if (this.TrackedInstances.TryGetValue(name, out obj2))
            {
                obj2.Detach();
                this.TrackedInstances.Remove(name);
            }
            ComplexObject obj3 = (ComplexObject) metaMember.GetValue(this);
            if (obj3 != null)
            {
                obj3.Attach(this, name, new Action(this.OnDataMemberChanging), new Action(this.OnDataMemberChanged), new Action<string, IEnumerable<ValidationResult>>(this.OnMemberValidationChanged));
                this.TrackedInstances[name] = obj3;
                if (obj3.HasValidationErrors)
                {
                    foreach (ValidationResult result in ValidationUtilities.ApplyMemberPath(obj3.ValidationErrors, name))
                    {
                        this.ValidationResultCollection.Add(result);
                    }
                }
            }
        }

        protected void BeginEdit()
        {
            if (!this.IsEditing)
            {
                this._editSession = EditSession.Begin(this);
            }
        }

        protected void CancelEdit()
        {
            if (this.IsEditing)
            {
                string[] modifiedProperties = this._editSession.ModifiedProperties.ToArray<string>();
                this._editSession.Cancel();
                this._editSession = null;
                this.UpdateRelatedAssociations(modifiedProperties);
            }
        }

        protected internal bool CanInvokeAction(string name)
        {
            this._lastCanInvoke = (((this._customMethodInvocation == null) && (this.EntityState != System.ServiceModel.DomainServices.Client.EntityState.Deleted)) && (this.EntitySet != null)) && !this.IsSubmitting;
            return this._lastCanInvoke;
        }

        private ValidationContext CreateValidationContext()
        {
            ValidationContext parentContext = null;
            if ((this.EntitySet != null) && (this.EntitySet.EntityContainer != null))
            {
                parentContext = this.EntitySet.EntityContainer.ValidationContext;
            }
            return ValidationUtilities.CreateValidationContext(this, parentContext);
        }

        protected void EndEdit()
        {
            if (this.IsEditing)
            {
                List<ValidationResult> validationResults = new List<ValidationResult>();
                ValidationUtilities.TryValidateObject(this, this.CreateValidationContext(), validationResults);
                ValidationUtilities.ApplyValidationErrors(this, validationResults);
                string[] modifiedProperties = this._editSession.ModifiedProperties.ToArray<string>();
                this._editSession = null;
                this.UpdateRelatedAssociations(modifiedProperties);
            }
        }

        internal IDictionary<string, object> ExtractState()
        {
            return ObjectStateUtility.ExtractState(this);
        }

        internal IEntityRef GetEntityRef(string memberName)
        {
            IEntityRef ref2 = null;
            this.EntityRefs.TryGetValue(memberName, out ref2);
            return ref2;
        }

        public virtual object GetIdentity()
        {
            PropertyInfo[] infoArray = (from p in this.MetaType.KeyMembers
                orderby p.Name
                select p).ToArray<PropertyInfo>();
            object[] keyValues = new object[infoArray.Length];
            for (int i = 0; i < infoArray.Length; i++)
            {
                object obj2 = infoArray[i].GetValue(this, null);
                if (obj2 == null)
                {
                    return null;
                }
                keyValues[i] = obj2;
            }
            if (keyValues.Length == 1)
            {
                return keyValues[0];
            }
            return EntityKey.Create(keyValues);
        }

        public Entity GetOriginal()
        {
            if (this.OriginalValues == null)
            {
                return null;
            }
            Entity entity = (Entity) Activator.CreateInstance(base.GetType());
            entity.ApplyState(this.OriginalValues);
            return entity;
        }

        internal void InitializeNew()
        {
            this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.New;
        }

        protected internal void InvokeAction(string actionName, params object[] parameters)
        {
            if (string.IsNullOrEmpty(actionName))
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resource.Parameter_NullOrEmpty, new object[] { "actionName" }));
            }
            if (this.IsSubmitting)
            {
                throw new InvalidOperationException(Resource.Entity_InvokeWhileSubmitting);
            }
            if (this.CustomMethodInvocation != null)
            {
                throw new InvalidOperationException(Resource.Entity_MultipleCustomMethodInvocations);
            }
            if (this._entityState == System.ServiceModel.DomainServices.Client.EntityState.Deleted)
            {
                throw new InvalidOperationException(Resource.Entity_InvokeOnDeletedEntity);
            }
            if (this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.Detached)
            {
                throw new InvalidOperationException(Resource.Entity_InvokeOnDetachedEntity);
            }
            Validator.ValidateObject(this, this.CreateValidationContext(), true);
            ValidationUtilities.ValidateCustomUpdateMethodCall(actionName, this.CreateValidationContext(), parameters);
            this.CustomMethodInvocation = new EntityAction(actionName, parameters);
        }

        protected bool IsActionInvoked(string name)
        {
            return Enumerable.Any<EntityAction>(this.EntityActions, (Func<EntityAction, bool>) (p => (p.Name == name)));
        }

        internal void MarkDeleted()
        {
            this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Deleted;
            this.CustomMethodInvocation = null;
            this.UpdateActionState(this._customMethodInvocation);
        }

        internal void MarkDetached()
        {
            this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Detached;
        }

        internal void MarkUnmodified()
        {
            this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Unmodified;
        }

        internal void Merge(Entity otherEntity, LoadBehavior loadBehavior)
        {
            if (loadBehavior != LoadBehavior.KeepCurrent)
            {
                this._isMerging = true;
                IDictionary<string, object> entityStateToApply = otherEntity.ExtractState();
                this.ApplyState(entityStateToApply, loadBehavior);
                if (this._originalValues != null)
                {
                    if (loadBehavior == LoadBehavior.RefreshCurrent)
                    {
                        this._originalValues = null;
                        if (((this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.Modified) && (this.CustomMethodInvocation == null)) && !this.HasChildChanges)
                        {
                            this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Unmodified;
                        }
                    }
                    else
                    {
                        this._originalValues = entityStateToApply;
                    }
                }
                this._isMerging = false;
                this.OnLoaded(false);
            }
        }

        protected virtual void OnActionStateChanged()
        {
        }

        internal void OnChildUpdate()
        {
            if (this._trackChanges && (this.EntityState != System.ServiceModel.DomainServices.Client.EntityState.Deleted))
            {
                bool hasChanges = this.HasChanges;
                this._hasChildChanges = this.LastSet.EntityContainer.HasChildChanges(this);
                if (!hasChanges && this._hasChildChanges)
                {
                    this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Modified;
                }
                else if ((hasChanges && !this._hasChildChanges) && ((this.CustomMethodInvocation == null) && !this.HasPropertyChanges))
                {
                    this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Unmodified;
                }
            }
            if (this.EntitySet != null)
            {
                this.EntitySet.TrackAsInteresting(this, true);
            }
        }

        private void OnDataMemberChanged()
        {
            if (((this.EntitySet != null) && !this._isMerging) && (this._trackChanges && (this.EntityState != System.ServiceModel.DomainServices.Client.EntityState.Modified)))
            {
                this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Modified;
            }
        }

        private void OnDataMemberChanging()
        {
            System.ServiceModel.DomainServices.Client.EntitySet lastSet = this.LastSet;
            if ((lastSet != null) && !this._isMerging)
            {
                if (this.EntityState != System.ServiceModel.DomainServices.Client.EntityState.New)
                {
                    lastSet.EnsureEditable(EntitySetOperations.Edit);
                }
                if (this._trackChanges && (this._originalValues == null))
                {
                    this._originalValues = this.ExtractState();
                }
            }
        }

        [OnDeserialized, EditorBrowsable(EditorBrowsableState.Never)]
        public void OnDeserialized(StreamingContext context)
        {
            this._isDeserializing = false;
        }

        [OnDeserializing, EditorBrowsable(EditorBrowsableState.Never)]
        public void OnDeserializing(StreamingContext context)
        {
            this._isDeserializing = true;
        }

        protected internal virtual void OnLoaded(bool isInitialLoad)
        {
        }

        private void OnMemberValidationChanged(string propertyName, IEnumerable<ValidationResult> validationResults)
        {
            this.ValidationResultCollection.ReplaceErrors(propertyName, validationResults);
        }

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }
            if (!this.IsEditing && (this.EntitySet != null))
            {
                this.EntitySet.UpdateRelatedAssociations(this, e.PropertyName);
            }
            if (this._propChangedHandler != null)
            {
                this._propChangedHandler(this, e);
            }
        }

        private bool PropertyHasChanged(PropertyInfo prop)
        {
            return ObjectStateUtility.PropertyHasChanged(this, this._originalValues, prop);
        }

        protected void RaiseDataMemberChanged(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentNullException("propertyName");
            }
            this.OnDataMemberChanged();
            this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
            if (this.MetaType.HasComplexMembers)
            {
                MetaMember metaMember = this.MetaType[propertyName];
                if (((metaMember != null) && metaMember.IsComplex) && !metaMember.IsCollection)
                {
                    this.AttachComplexObjectInstance(metaMember);
                }
            }
        }

        protected void RaiseDataMemberChanging(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentNullException("propertyName");
            }
            this.OnDataMemberChanging();
            if (this.IsEditing)
            {
                this._editSession.OnDataMemberUpdate(propertyName);
            }
        }

        protected internal void RaisePropertyChanged(string propertyName)
        {
            this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }

        private void RaiseValidationErrorsChanged(string propertyName)
        {
            EventHandler<DataErrorsChangedEventArgs> handler = this._validationErrorsChanged;
            if (handler != null)
            {
                handler(this, new DataErrorsChangedEventArgs(propertyName));
            }
        }

        internal void RegisterSetChangedCallback(Action callback)
        {
            this._setChangedCallback = (Action) Delegate.Combine(this._setChangedCallback, callback);
        }

        protected void RejectChanges()
        {
            if ((this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.Unmodified) || (this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.Detached))
            {
                this._editSession = null;
            }
            else
            {
                System.ServiceModel.DomainServices.Client.EntitySet lastSet = this.LastSet;
                if (lastSet != null)
                {
                    lastSet.EntityContainer.CompleteChildChanges(this, false);
                }
                if ((this._entityState == System.ServiceModel.DomainServices.Client.EntityState.Modified) || (this.Parent != null))
                {
                    if ((lastSet != null) && (this.Parent != null))
                    {
                        if (this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.Deleted)
                        {
                            lastSet.Add(this);
                        }
                        else if (this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.New)
                        {
                            lastSet.Remove(this);
                            this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Detached;
                        }
                    }
                    if (this._originalValues != null)
                    {
                        this.ApplyState(this._originalValues);
                        this._originalValues = null;
                    }
                    if ((lastSet != null) && (this.EntityState == System.ServiceModel.DomainServices.Client.EntityState.Modified))
                    {
                        this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Unmodified;
                        lastSet.TrackAsInteresting(this, false);
                    }
                }
                this._editSession = null;
                this.CustomMethodInvocation = null;
                if (this._validationErrors != null)
                {
                    this._validationErrors.Clear();
                }
                this.EntityConflict = null;
                this._hasChildChanges = false;
            }
        }

        internal void Reset()
        {
            this._originalValues = null;
            this._editSession = null;
            this._trackChanges = false;
            this.CustomMethodInvocation = null;
            if (this._validationErrors != null)
            {
                this._validationErrors.Clear();
            }
            this.EntityConflict = null;
            this.EntitySet = null;
            this._lastSet = null;
            this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Detached;
            this._hasChildChanges = false;
        }

        internal void SetEntityRef(string memberName, IEntityRef entityRef)
        {
            this.EntityRefs[memberName] = entityRef;
        }

        internal void SetParent(Entity parent, AssociationAttribute association)
        {
            if (this._parent != parent)
            {
                if (parent == this)
                {
                    throw new InvalidOperationException(Resource.Entity_ChildCannotBeItsParent);
                }
                this._parent = parent;
            }
            this._parentAssociation = association;
        }

        internal void StartTracking()
        {
            this._trackChanges = true;
        }

        internal void StopTracking()
        {
            this._trackChanges = false;
        }

        void IChangeTracking.AcceptChanges()
        {
            this.AcceptChanges();
        }

        void IEditableObject.BeginEdit()
        {
            this.BeginEdit();
        }

        void IEditableObject.CancelEdit()
        {
            this.CancelEdit();
        }

        void IEditableObject.EndEdit()
        {
            this.EndEdit();
        }

        IEnumerable INotifyDataErrorInfo.GetErrors(string propertyName)
        {
            IEnumerable<ValidationResult> enumerable;
            Func<ValidationResult, bool> func = null;
            Func<ValidationResult, bool> func2 = null;
            if (string.IsNullOrEmpty(propertyName))
            {
                if (func == null)
                {
                    func = delegate (ValidationResult e) {
                        if (e.MemberNames.Any<string>())
                        {
                            return e.MemberNames.Contains<string>(propertyName);
                        }
                        return true;
                    };
                }
                enumerable = Enumerable.Where<ValidationResult>(this.ValidationErrors, func);
            }
            else
            {
                if (func2 == null)
                {
                    func2 = e => e.MemberNames.Contains<string>(propertyName);
                }
                enumerable = Enumerable.Where<ValidationResult>(this.ValidationErrors, func2);
            }
            return enumerable.ToArray<ValidationResult>();
        }

        void IRevertibleChangeTracking.RejectChanges()
        {
            this.RejectChanges();
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder();
            PropertyInfo[] infoArray = this.MetaType.KeyMembers.ToArray<PropertyInfo>();
            foreach (PropertyInfo info in from m in infoArray
                orderby m.Name
                select m)
            {
                if (builder.Length > 0)
                {
                    builder.Append(",");
                }
                object obj2 = info.GetValue(this, null);
                builder.Append((obj2 != null) ? obj2.ToString() : "null");
            }
            string str = (infoArray.Length > 1) ? ("{" + builder.ToString() + "}") : builder.ToString();
            return string.Format(CultureInfo.CurrentCulture, "{0} : {1}", new object[] { base.GetType().Name, str });
        }

        internal void UndoDelete()
        {
            if (this._originalValues != null)
            {
                this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Modified;
            }
            else
            {
                this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Unmodified;
            }
            this.UpdateActionState(this._customMethodInvocation);
        }

        private void UpdateActionState(EntityAction prevCustomMethodInvocation)
        {
            if (this._lastCanInvoke != this.CanInvokeAction(null))
            {
                this._prevCustomMethodInvocation = prevCustomMethodInvocation;
                this.OnActionStateChanged();
                this._prevCustomMethodInvocation = null;
            }
        }

        protected void UpdateActionState(string name, string canInvokePropertyName, string isInvokedPropertyName)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }
            if (string.IsNullOrEmpty(canInvokePropertyName))
            {
                throw new ArgumentNullException("canInvokePropertyName");
            }
            if (string.IsNullOrEmpty(isInvokedPropertyName))
            {
                throw new ArgumentNullException("isInvokedPropertyName");
            }
            this.RaisePropertyChanged(canInvokePropertyName);
            bool flag = ((this._prevCustomMethodInvocation != null) && (this._customMethodInvocation == null)) && (this._prevCustomMethodInvocation.Name == name);
            bool flag2 = ((this._customMethodInvocation != null) && (this._prevCustomMethodInvocation == null)) && (this._customMethodInvocation.Name == name);
            if (flag || flag2)
            {
                this.RaisePropertyChanged(isInvokedPropertyName);
            }
        }

        internal void UpdateOriginalValues(Entity entity)
        {
            this._originalValues = entity.ExtractState();
        }

        private void UpdateRelatedAssociations(IEnumerable<string> modifiedProperties)
        {
            if (this.EntitySet != null)
            {
                foreach (string str in modifiedProperties)
                {
                    this.EntitySet.UpdateRelatedAssociations(this, str);
                }
            }
        }

        protected virtual void ValidateProperty(ValidationContext validationContext, object value)
        {
            if (validationContext == null)
            {
                throw new ArgumentNullException("validationContext");
            }
            List<ValidationResult> validationResults = new List<ValidationResult>();
            Validator.TryValidateProperty(value, validationContext, validationResults);
            this.ValidationResultCollection.ReplaceErrors(validationContext.MemberName, validationResults);
        }

        protected void ValidateProperty(string propertyName, object value)
        {
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentNullException("propertyName");
            }
            if (!this.IsDeserializing && !this.IsApplyingState)
            {
                if ((this.EntitySet != null) && (this.EntityState != System.ServiceModel.DomainServices.Client.EntityState.New))
                {
                    this.EntitySet.EnsureEditable(EntitySetOperations.Edit);
                }
                if (this.IsReadOnly)
                {
                    throw new InvalidOperationException(Resource.Entity_ReadOnly);
                }
                MetaMember member = this.MetaType[propertyName];
                if (member == null)
                {
                    throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resource.Property_Does_Not_Exist, new object[] { this.MetaType.Type.Name, propertyName }), "propertyName");
                }
                if (((member.EditableAttribute != null) && !member.EditableAttribute.AllowEdit) && (!member.EditableAttribute.AllowInitialValue || ((this.EntityState != System.ServiceModel.DomainServices.Client.EntityState.Detached) && (this.EntityState != System.ServiceModel.DomainServices.Client.EntityState.New))))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.Property_Is_ReadOnly, new object[] { propertyName }));
                }
                ComplexObject obj2 = value as ComplexObject;
                if ((obj2 != null) && obj2.IsAttached)
                {
                    throw new InvalidOperationException(Resource.ComplexType_InstancesCannotBeShared);
                }
                if (this.MetaType.RequiresValidation)
                {
                    ValidationContext validationContext = this.CreateValidationContext();
                    validationContext.MemberName = propertyName;
                    this.ValidateProperty(validationContext, value);
                }
            }
        }

        internal void VerifyNotEditing()
        {
            if (this.IsEditing)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.Entity_UncommittedChanges, new object[] { this }));
            }
            foreach (ComplexObject obj2 in this.TrackedInstances.Values)
            {
                obj2.VerifyNotEditing();
            }
        }

        internal EntityAction CustomMethodInvocation
        {
            get
            {
                return this._customMethodInvocation;
            }
            set
            {
                if (this._customMethodInvocation != value)
                {
                    bool isReadOnly = this.IsReadOnly;
                    EntityAction prevCustomMethodInvocation = this._customMethodInvocation;
                    this._customMethodInvocation = value;
                    if ((value != null) && (this._entityState == System.ServiceModel.DomainServices.Client.EntityState.Unmodified))
                    {
                        this.EntityState = System.ServiceModel.DomainServices.Client.EntityState.Modified;
                    }
                    if (isReadOnly != this.IsReadOnly)
                    {
                        this.RaisePropertyChanged("IsReadOnly");
                    }
                    this.UpdateActionState(prevCustomMethodInvocation);
                }
            }
        }

        [Display(AutoGenerateField=false)]
        public IEnumerable<EntityAction> EntityActions
        {
            get
            {
                if (this._customMethodInvocation != null)
                {
                    return new EntityAction[] { this._customMethodInvocation };
                }
                return Enumerable.Empty<EntityAction>();
            }
        }

        [Display(AutoGenerateField=false)]
        public System.ServiceModel.DomainServices.Client.EntityConflict EntityConflict
        {
            get
            {
                return this._conflict;
            }
            internal set
            {
                if (this._conflict != value)
                {
                    this._conflict = value;
                    this.RaisePropertyChanged("EntityConflict");
                }
            }
        }

        private IDictionary<string, IEntityRef> EntityRefs
        {
            get
            {
                if (this._entityRefs == null)
                {
                    this._entityRefs = new Dictionary<string, IEntityRef>();
                }
                return this._entityRefs;
            }
        }

        protected internal System.ServiceModel.DomainServices.Client.EntitySet EntitySet
        {
            get
            {
                return this._entitySet;
            }
            internal set
            {
                this._entitySet = value;
                if (value != null)
                {
                    this._lastSet = value;
                }
                this.UpdateActionState(this._customMethodInvocation);
                if (this._setChangedCallback != null)
                {
                    this._setChangedCallback();
                }
            }
        }

        [Display(AutoGenerateField=false)]
        public System.ServiceModel.DomainServices.Client.EntityState EntityState
        {
            get
            {
                return this._entityState;
            }
            private set
            {
                if (this._entityState != value)
                {
                    bool flag = ((this._entityState == System.ServiceModel.DomainServices.Client.EntityState.Modified) && (value == System.ServiceModel.DomainServices.Client.EntityState.Unmodified)) || ((this._entityState == System.ServiceModel.DomainServices.Client.EntityState.Unmodified) && (value == System.ServiceModel.DomainServices.Client.EntityState.Modified));
                    this._entityState = value;
                    this.RaisePropertyChanged("EntityState");
                    System.ServiceModel.DomainServices.Client.EntitySet lastSet = this.LastSet;
                    if (lastSet != null)
                    {
                        bool isInteresting = (this._entityState != System.ServiceModel.DomainServices.Client.EntityState.Unmodified) && (this._entityState != System.ServiceModel.DomainServices.Client.EntityState.Detached);
                        lastSet.TrackAsInteresting(this, isInteresting);
                    }
                    if (flag)
                    {
                        this.RaisePropertyChanged("HasChanges");
                        if ((this.Parent != null) && this._trackChanges)
                        {
                            this.Parent.OnChildUpdate();
                        }
                    }
                }
            }
        }

        [Display(AutoGenerateField=false)]
        public bool HasChanges
        {
            get
            {
                return (this._entityState == System.ServiceModel.DomainServices.Client.EntityState.Modified);
            }
        }

        internal bool HasChildChanges
        {
            get
            {
                return this._hasChildChanges;
            }
        }

        internal bool HasPropertyChanges
        {
            get
            {
                return (this._originalValues != null);
            }
        }

        [Display(AutoGenerateField=false)]
        public bool HasValidationErrors
        {
            get
            {
                return this.ValidationErrors.Any<ValidationResult>();
            }
        }

        internal bool IsApplyingState
        {
            get
            {
                return this._isApplyingState;
            }
        }

        protected internal bool IsDeserializing
        {
            get
            {
                return this._isDeserializing;
            }
        }

        internal bool IsEditing
        {
            get
            {
                return (this._editSession != null);
            }
        }

        internal bool IsInferred
        {
            get
            {
                return this._isInferred;
            }
            set
            {
                this._isInferred = value;
            }
        }

        internal bool IsMergingState
        {
            get
            {
                return this._isMerging;
            }
        }

        [Display(AutoGenerateField=false)]
        public bool IsReadOnly
        {
            get
            {
                if (this.IsApplyingState)
                {
                    return false;
                }
                if (((this.EntitySet != null) && (this.EntityState != System.ServiceModel.DomainServices.Client.EntityState.New)) && !this.EntitySet.CanEdit)
                {
                    return true;
                }
                if (this.IsSubmitting)
                {
                    return true;
                }
                bool flag = this.HasValidationErrors || (this.EntityConflict != null);
                return ((this._customMethodInvocation != null) && !flag);
            }
        }

        internal bool IsSubmitting
        {
            get
            {
                return this._isSubmitting;
            }
            set
            {
                if (this._isSubmitting != value)
                {
                    bool isReadOnly = this.IsReadOnly;
                    this._isSubmitting = value;
                    if (isReadOnly != this.IsReadOnly)
                    {
                        this.RaisePropertyChanged("IsReadOnly");
                    }
                }
            }
        }

        internal System.ServiceModel.DomainServices.Client.EntitySet LastSet
        {
            get
            {
                if (this.EntitySet == null)
                {
                    return this._lastSet;
                }
                return this.EntitySet;
            }
        }

        internal System.ServiceModel.DomainServices.Client.MetaType MetaType
        {
            get
            {
                if (this._metaType == null)
                {
                    this._metaType = System.ServiceModel.DomainServices.Client.MetaType.GetMetaType(base.GetType());
                }
                return this._metaType;
            }
        }

        internal IEnumerable<PropertyInfo> ModifiedProperties
        {
            get
            {
                return (from p in this.MetaType.DataMembers
                    select p.Member into p
                    where this.PropertyHasChanged(p)
                    select p);
            }
        }

        internal IDictionary<string, object> OriginalValues
        {
            get
            {
                return this._originalValues;
            }
        }

        internal Entity Parent
        {
            get
            {
                return this._parent;
            }
        }

        internal AssociationAttribute ParentAssociation
        {
            get
            {
                return this._parentAssociation;
            }
        }

        bool IChangeTracking.IsChanged
        {
            get
            {
                return this.HasChanges;
            }
        }

        bool INotifyDataErrorInfo.HasErrors
        {
            get
            {
                return this.HasValidationErrors;
            }
        }

        private Dictionary<string, ComplexObject> TrackedInstances
        {
            get
            {
                if (this._trackedInstances == null)
                {
                    this._trackedInstances = new Dictionary<string, ComplexObject>();
                }
                return this._trackedInstances;
            }
        }

        [Display(AutoGenerateField=false)]
        public ICollection<ValidationResult> ValidationErrors
        {
            get
            {
                if (this._validationErrors == null)
                {
                    this._validationErrors = new EntityValidationResultCollection(this);
                }
                return this._validationErrors;
            }
        }

        internal System.ServiceModel.DomainServices.Client.ValidationResultCollection ValidationResultCollection
        {
            get
            {
                return (System.ServiceModel.DomainServices.Client.ValidationResultCollection) this.ValidationErrors;
            }
        }

        private class EditSession
        {
            private EntityAction _customMethodInvocation;
            private Entity _entity;
            private EntityState _lastState;
            private List<string> _modifiedProperties;
            private IDictionary<string, object> _snapshot;
            private ValidationResult[] _validationErrors;

            private EditSession(Entity entity)
            {
                this._entity = entity;
                this._lastState = entity.EntityState;
                this._customMethodInvocation = entity.CustomMethodInvocation;
                this._validationErrors = entity.ValidationErrors.ToArray<ValidationResult>();
                this._modifiedProperties = new List<string>();
            }

            public static Entity.EditSession Begin(Entity entity)
            {
                return new Entity.EditSession(entity);
            }

            public void Cancel()
            {
                if (this._lastState == EntityState.Unmodified)
                {
                    this._entity.RejectChanges();
                }
                else
                {
                    if (this._snapshot != null)
                    {
                        this._entity.ApplyState(this._snapshot);
                    }
                    this._entity.CustomMethodInvocation = this._customMethodInvocation;
                }
                ValidationUtilities.ApplyValidationErrors(this._entity, this._validationErrors);
            }

            public void OnDataMemberUpdate(string memberName)
            {
                if (this._snapshot == null)
                {
                    this._snapshot = this._entity.ExtractState();
                }
                if (!this._modifiedProperties.Contains(memberName))
                {
                    this._modifiedProperties.Add(memberName);
                }
            }

            public IEnumerable<string> ModifiedProperties
            {
                get
                {
                    return this._modifiedProperties;
                }
            }
        }

        private class EntityValidationResultCollection : ValidationResultCollection
        {
            private Entity _entity;

            public EntityValidationResultCollection(Entity entity) : base(entity)
            {
                this._entity = entity;
            }

            protected override void OnCollectionChanged()
            {
                this._entity.RaisePropertyChanged("ValidationErrors");
            }

            protected override void OnHasErrorsChanged()
            {
                this._entity.RaisePropertyChanged("HasValidationErrors");
            }

            protected override void OnPropertyErrorsChanged(string propertyName)
            {
                this._entity.RaiseValidationErrorsChanged(propertyName);
            }
        }
    }
}

